#ifndef __POINT2D_H__
#define __POINT2D_H__

////////////////////////////////////////////////////////////////////////////////
// Includes
////////////////////////////////////////////////////////////////////////////////

#include "Vector2D.hpp"
#include <iostream>

////////////////////////////////////////////////////////////////////////////////
// Namespaces
////////////////////////////////////////////////////////////////////////////////

namespace Types {

////////////////////////////////////////////////////////////////////////////////
// Implementation
////////////////////////////////////////////////////////////////////////////////

/// Point 2D type
template <typename T>
class Point2D {

	public:
		
		/// Constructor
		Point2D() {}
		
		/// Constructor with initialisation values
		Point2D(const T & x, const T & y) : x(x), y(y) {}

		/// Create a copy of the given instance
		template <typename T2>
		Point2D(const Point2D<T2> & inst)
		: x(static_cast<T>(inst.x)), y(static_cast<T>(inst.y)) {}

		/// Affectation operator
		template <typename T2>
		Point2D<T> & operator = (const Point2D<T2> & inst) {
			if (this != &inst) {
				this->x	= static_cast<T>(inst.x);
				this->y = static_cast<T>(inst.y);
			}
			return *this;
		}

		/// Returns true if the vector is null
		const bool IsNull() const {
			return (this->x ==  static_cast<T>(0)) && (this->y ==  static_cast<T>(0));
		}
		
		/// Comparison operator ==
		const bool operator== (const Point2D<T> & p) const {
			return (this->x == p.x) && (this->y == p.y);
		}
		
		/// Comparison operator !=
		const bool operator!= (const Point2D<T> & p) const {
			return (this->x != p.x) || (this->y != p.y);
		}
		
		/// Output operator
		//friend std::ostream & operator << (std::ostream & stream, const Point2D & p) {
		//	return (stream << "( " << p.x << ", " << p.y << " )");
		//}

		/// Add a vector to a point
		const Point2D<T> operator+ (const Vector2D<T> & v) const {
			return Point2D<T> ( this->x + v.x, this->y + v.y );
		}

		/// Add a vector to the current point
		void operator+= (const Vector2D<T> & v) {
			this->x += v.x; this->y += v.y;
		}

		/// Substract a vector from the current point
		void operator-= (const Vector2D<T> & v) {
			this->x -= v.x; this->y -= v.y;
		}
		
		/// Substract a vector from a point
		const Point2D<T> operator- (const Vector2D<T> & v) const {
			return Point2D<T> ( this->x - v.x, this->y - v.y );
		}
		
		/// Create a vector out of the substraction of two points
		const Vector2D<T> operator- (const Point2D<T> & p) const {
			return Vector2D<T> ( this->x - p.x, this->y - p.y );
		}

		/// Coordinates
		T x, y;

};

////////////////////////////////////////////////////////////////////////////////
// Closing Namespaces
////////////////////////////////////////////////////////////////////////////////

}

////////////////////////////////////////////////////////////////////////////////

#else

namespace Types {
	template <typename T> class Point2D;
}

#endif
